import os
import sys
import datetime
from typing import List, Dict, Any, Optional
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                            QLabel, QLineEdit, QPushButton, QFileDialog, QTableWidget,
                            QTableWidgetItem, QHeaderView, QCheckBox, QDateEdit, QSpinBox,
                            QComboBox, QProgressBar, QSplitter, QTextEdit, QTabWidget,
                            QFrame, QSystemTrayIcon, QMenu, QAction, QMessageBox, QStyle,
                            QStyledItemDelegate, QAbstractItemView)
from PyQt5.QtCore import Qt, QSize, QThread, pyqtSignal, QDate, QDateTime, QPoint, QSortFilterProxyModel
from PyQt5.QtGui import QIcon, QPixmap, QColor, QFont, QTextDocument, QTextCursor

from src.search_engine import FileSearchEngine
from src.utils import get_app_icon, format_file_size

# 文件类型图标映射
FILE_TYPE_ICONS = {
    'text': ('text-file', QStyle.SP_FileIcon),
    'image': ('image-file', QStyle.SP_DirIcon),
    'audio': ('audio-file', QStyle.SP_MediaVolume),
    'video': ('video-file', QStyle.SP_MediaPlay),
    'document': ('document-file', QStyle.SP_FileDialogDetailedView),
    'spreadsheet': ('spreadsheet-file', QStyle.SP_FileDialogDetailedView),
    'presentation': ('presentation-file', QStyle.SP_FileDialogDetailedView),
    'archive': ('archive-file', QStyle.SP_DirLinkIcon),
    'executable': ('executable-file', QStyle.SP_FileLinkIcon),
    'folder': ('folder', QStyle.SP_DirIcon),
    'default': ('file', QStyle.SP_FileIcon)
}

class FileSearchUI(QMainWindow):
    """文件搜索应用的主窗口"""
    
    def __init__(self, app):
        super().__init__()
        self.app = app
        self.search_engine = FileSearchEngine()
        self.init_ui()
        
    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle("本地文件搜索引擎")
        self.setGeometry(100, 100, 1000, 700)
        self.setWindowIcon(self.get_icon('search'))
        
        # 主布局
        main_layout = QVBoxLayout()
        main_widget = QWidget()
        main_widget.setLayout(main_layout)
        self.setCentralWidget(main_widget)
        
        # 搜索区域
        search_frame = QFrame()
        search_frame.setFrameShape(QFrame.StyledPanel)
        search_layout = QVBoxLayout(search_frame)
        
        # 第一行: 目录选择
        dir_layout = QHBoxLayout()
        dir_label = QLabel("搜索目录:")
        self.dir_input = QLineEdit()
        self.dir_input.setReadOnly(True)
        browse_btn = QPushButton("浏览...")
        browse_btn.clicked.connect(self.browse_directory)
        dir_layout.addWidget(dir_label)
        dir_layout.addWidget(self.dir_input)
        dir_layout.addWidget(browse_btn)
        search_layout.addLayout(dir_layout)
        
        # 第二行: 文件名和内容搜索
        name_content_layout = QHBoxLayout()
        
        # 文件名
        name_label = QLabel("文件名:")
        self.name_input = QLineEdit()
        self.name_input.setPlaceholderText("输入文件名或正则表达式")
        name_content_layout.addWidget(name_label)
        name_content_layout.addWidget(self.name_input)
        
        # 文件内容
        content_label = QLabel("文件内容:")
        self.content_input = QLineEdit()
        self.content_input.setPlaceholderText("输入要搜索的文本内容")
        name_content_layout.addWidget(content_label)
        name_content_layout.addWidget(self.content_input)
        
        search_layout.addLayout(name_content_layout)
        
        # 第三行: 过滤条件
        filter_layout = QHBoxLayout()
        
        # 文件大小
        size_label = QLabel("文件大小:")
        self.min_size_spin = QSpinBox()
        self.min_size_spin.setRange(0, 1000000)
        self.min_size_spin.setSuffix(" KB")
        self.min_size_spin.setSpecialValueText("最小")
        
        size_to_label = QLabel("到")
        
        self.max_size_spin = QSpinBox()
        self.max_size_spin.setRange(0, 1000000)
        self.max_size_spin.setSuffix(" KB")
        self.max_size_spin.setSpecialValueText("最大")
        self.max_size_spin.setValue(0)
        
        filter_layout.addWidget(size_label)
        filter_layout.addWidget(self.min_size_spin)
        filter_layout.addWidget(size_to_label)
        filter_layout.addWidget(self.max_size_spin)
        
        # 修改日期
        date_label = QLabel("修改日期:")
        self.min_date_edit = QDateEdit()
        self.min_date_edit.setCalendarPopup(True)
        self.min_date_edit.setDate(QDate.currentDate().addYears(-1))
        self.min_date_edit.setSpecialValueText("最早")
        
        date_to_label = QLabel("到")
        
        self.max_date_edit = QDateEdit()
        self.max_date_edit.setCalendarPopup(True)
        self.max_date_edit.setDate(QDate.currentDate())
        self.max_date_edit.setSpecialValueText("最近")
        
        date_layout = QHBoxLayout()
        date_layout.addWidget(date_label)
        date_layout.addWidget(self.min_date_edit)
        date_layout.addWidget(date_to_label)
        date_layout.addWidget(self.max_date_edit)
        
        # 启用日期过滤
        self.use_date_filter = QCheckBox("按日期筛选")
        date_layout.addWidget(self.use_date_filter)
        
        filter_layout.addLayout(date_layout)
        
        # 文件类型选择
        type_label = QLabel("文件类型:")
        self.type_combo = QComboBox()
        self.type_combo.addItem("所有文件", None)
        self.type_combo.addItem("文档", ["text/plain", "application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"])
        self.type_combo.addItem("图片", ["image/jpeg", "image/png", "image/gif"])
        self.type_combo.addItem("音频", ["audio/mpeg", "audio/wav"])
        self.type_combo.addItem("视频", ["video/mp4", "video/quicktime"])
        self.type_combo.addItem("压缩文件", ["application/zip", "application/x-rar-compressed"])
        
        filter_layout.addWidget(type_label)
        filter_layout.addWidget(self.type_combo)
        
        search_layout.addLayout(filter_layout)
        
        # 第四行: 搜索按钮和进度条
        btn_progress_layout = QHBoxLayout()
        
        self.search_btn = QPushButton("开始搜索")
        self.search_btn.setIcon(self.get_icon('search'))
        self.search_btn.clicked.connect(self.start_search)
        
        self.stop_btn = QPushButton("停止")
        self.stop_btn.setIcon(self.get_icon('stop'))
        self.stop_btn.clicked.connect(self.stop_search)
        self.stop_btn.setEnabled(False)
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setTextVisible(True)
        self.progress_bar.setAlignment(Qt.AlignCenter)
        self.progress_bar.setFormat("已处理: %v 个文件")
        
        btn_progress_layout.addWidget(self.search_btn)
        btn_progress_layout.addWidget(self.stop_btn)
        btn_progress_layout.addWidget(self.progress_bar)
        
        search_layout.addLayout(btn_progress_layout)
        
        main_layout.addWidget(search_frame)
        
        # 结果区域
        splitter = QSplitter(Qt.Vertical)
        
        # 结果表格
        self.result_table = QTableWidget()
        self.result_table.setColumnCount(5)
        self.result_table.setHorizontalHeaderLabels(["文件名", "路径", "大小", "修改日期", "类型"])
        self.result_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)  # 路径列自适应
        self.result_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.result_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.result_table.setSortingEnabled(True)
        self.result_table.setAlternatingRowColors(True)
        self.result_table.itemDoubleClicked.connect(self.open_file)
        splitter.addWidget(self.result_table)
        
        # 文件预览标签页
        self.preview_tabs = QTabWidget()
        self.preview_tabs.setTabPosition(QTabWidget.South)
        
        # 文本预览
        self.text_preview = QTextEdit()
        self.text_preview.setReadOnly(True)
        self.preview_tabs.addTab(self.text_preview, "文本预览")
        
        # 统计信息
        self.stats_widget = QWidget()
        stats_layout = QVBoxLayout(self.stats_widget)
        self.stats_label = QLabel("搜索统计")
        self.stats_label.setAlignment(Qt.AlignCenter)
        stats_layout.addWidget(self.stats_label)
        
        self.preview_tabs.addTab(self.stats_widget, "统计信息")
        
        splitter.addWidget(self.preview_tabs)
        
        # 设置分割比例
        splitter.setSizes([500, 200])
        
        main_layout.addWidget(splitter)
        
        # 状态栏
        self.statusBar().showMessage("就绪")
        
        # 连接信号
        self.result_table.itemSelectionChanged.connect(self.update_preview)
        
        # 显示窗口
        self.show()
    
    def get_icon(self, name: str) -> QIcon:
        """获取图标"""
        if name == 'search':
            return get_app_icon(name, QStyle.SP_FileDialogContentsView)
        elif name == 'stop':
            return get_app_icon(name, QStyle.SP_BrowserStop)
        else:
            # 处理文件类型图标
            if name in FILE_TYPE_ICONS:
                icon_name, default_icon = FILE_TYPE_ICONS[name]
                return get_app_icon(icon_name, default_icon)
            return get_app_icon('file', QStyle.SP_FileIcon)
    
    def browse_directory(self):
        """选择搜索目录"""
        dir_path = QFileDialog.getExistingDirectory(self, "选择搜索目录")
        if dir_path:
            self.dir_input.setText(dir_path)
    
    def start_search(self):
        """开始搜索"""
        search_dir = self.dir_input.text()
        if not search_dir:
            QMessageBox.warning(self, "警告", "请选择搜索目录")
            return
            
        # 获取搜索参数
        filename_pattern = self.name_input.text()
        content_pattern = self.content_input.text()
        
        # 文件大小筛选（转换为字节）
        min_size = self.min_size_spin.value() * 1024 if self.min_size_spin.value() > 0 else None
        max_size = self.max_size_spin.value() * 1024 if self.max_size_spin.value() > 0 else None
        
        # 日期筛选
        min_date = None
        max_date = None
        if self.use_date_filter.isChecked():
            min_date = datetime.datetime.combine(
                self.min_date_edit.date().toPython(),
                datetime.time.min
            )
            max_date = datetime.datetime.combine(
                self.max_date_edit.date().toPython(),
                datetime.time.max
            )
        
        # 文件类型筛选
        file_types = self.type_combo.currentData()
        
        # 更新UI状态
        self.search_btn.setEnabled(False)
        self.stop_btn.setEnabled(True)
        self.result_table.setRowCount(0)
        self.progress_bar.setValue(0)
        self.statusBar().showMessage("正在搜索...")
        
        # 开始搜索
        self.search_engine.search(
            root_dir=search_dir,
            filename_pattern=filename_pattern,
            content_pattern=content_pattern,
            min_size=min_size,
            max_size=max_size,
            min_date=min_date,
            max_date=max_date,
            file_types=file_types,
            progress_callback=self.update_progress
        )
        
        # 启动结果更新定时器
        self._result_timer = self.startTimer(500)  # 每500毫秒更新一次结果
    
    def stop_search(self):
        """停止搜索"""
        self.search_engine.stop_search()
        self.stop_btn.setEnabled(False)
        self.search_btn.setEnabled(True)
        self.statusBar().showMessage("搜索已停止")
    
    def update_progress(self, count: int, current_file: str):
        """更新进度条"""
        self.progress_bar.setValue(count)
        self.statusBar().showMessage(f"正在扫描: {current_file}")
    
    def timerEvent(self, event):
        """定时器事件，用于更新搜索结果"""
        if not self.search_engine.is_searching:
            # 搜索完成，停止定时器
            self.killTimer(self._result_timer)
            self.search_btn.setEnabled(True)
            self.stop_btn.setEnabled(False)
            self.statusBar().showMessage(f"搜索完成。找到 {len(self.search_engine.search_results)} 个结果。")
            
        # 更新结果表格
        self.update_results_table()
    
    def update_results_table(self):
        """更新结果表格"""
        results = self.search_engine.get_results()
        self.result_table.setRowCount(len(results))
        
        for row, result in enumerate(results):
            # 文件名带图标
            name_item = QTableWidgetItem(result['name'])
            file_type = result['type'].split('/')[0]
            icon_name = 'default'
            if file_type in ('text', 'image', 'audio', 'video'):
                icon_name = f"{file_type}"
            elif file_type == 'application':
                if 'pdf' in result['type'] or 'word' in result['type'] or 'document' in result['type']:
                    icon_name = 'document'
                elif 'spreadsheet' in result['type'] or 'excel' in result['type']:
                    icon_name = 'spreadsheet'
                elif 'presentation' in result['type'] or 'powerpoint' in result['type']:
                    icon_name = 'presentation'
                elif 'zip' in result['type'] or 'rar' in result['type'] or 'compressed' in result['type']:
                    icon_name = 'archive'
                elif 'executable' in result['type'] or 'msdownload' in result['type']:
                    icon_name = 'executable'
            
            name_item.setIcon(self.get_icon(icon_name))
            self.result_table.setItem(row, 0, name_item)
            
            # 路径
            path_item = QTableWidgetItem(result['path'])
            self.result_table.setItem(row, 1, path_item)
            
            # 文件大小
            size_text = format_file_size(result['size'])
            size_item = QTableWidgetItem(size_text)
            size_item.setData(Qt.UserRole, result['size'])  # 用于排序
            self.result_table.setItem(row, 2, size_item)
            
            # 修改日期
            date_text = result['modified'].strftime("%Y-%m-%d %H:%M:%S")
            date_item = QTableWidgetItem(date_text)
            date_item.setData(Qt.UserRole, result['modified'].timestamp())  # 用于排序
            self.result_table.setItem(row, 3, date_item)
            
            # 文件类型
            type_item = QTableWidgetItem(result['type'])
            self.result_table.setItem(row, 4, type_item)
        
        # 更新统计信息
        self.update_statistics(results)
    
    def update_statistics(self, results: List[Dict[str, Any]]):
        """更新统计信息"""
        if not results:
            self.stats_label.setText("没有找到结果")
            return
            
        # 计算统计数据
        total_size = sum(r['size'] for r in results)
        avg_size = total_size / len(results)
        
        # 按类型统计
        type_counts = {}
        for r in results:
            main_type = r['type'].split('/')[0]
            if main_type not in type_counts:
                type_counts[main_type] = 0
            type_counts[main_type] += 1
        
        # 格式化统计信息
        stats_text = f"""
        <h3>搜索统计</h3>
        <p><b>找到文件数:</b> {len(results)}</p>
        <p><b>总大小:</b> {format_file_size(total_size)}</p>
        <p><b>平均大小:</b> {format_file_size(avg_size)}</p>
        <h4>文件类型分布:</h4>
        <ul>
        """
        
        for t, count in type_counts.items():
            stats_text += f"<li><b>{t}:</b> {count} 个文件 ({count/len(results)*100:.1f}%)</li>"
        
        stats_text += "</ul>"
        
        self.stats_label.setText(stats_text)
    
    def update_preview(self):
        """更新文件预览"""
        selected_items = self.result_table.selectedItems()
        if not selected_items:
            return
            
        # 获取选中行
        row = selected_items[0].row()
        file_path = self.result_table.item(row, 1).text()
        file_type = self.result_table.item(row, 4).text()
        
        # 显示文本预览
        if file_type.startswith('text/') or file_type in ('application/json', 'application/xml', 'application/javascript'):
            try:
                with open(file_path, 'r', errors='ignore') as f:
                    content = f.read(10000)  # 最多读取10KB
                    if len(content) == 10000:
                        content += '\n\n[文件太大，只显示部分内容...]'
                self.text_preview.setText(content)
                self.preview_tabs.setCurrentIndex(0)  # 切换到文本预览标签
            except Exception as e:
                self.text_preview.setText(f"无法预览文件内容: {str(e)}")
        else:
            self.text_preview.setText(f"无法预览该类型的文件: {file_type}")
            self.preview_tabs.setCurrentIndex(1)  # 切换到统计信息标签
    
    def open_file(self, item):
        """打开选中的文件"""
        row = item.row()
        file_path = self.result_table.item(row, 1).text()
        
        try:
            if sys.platform == 'win32':
                os.startfile(file_path)
            elif sys.platform == 'darwin':  # macOS
                import subprocess
                subprocess.call(['open', file_path])
            else:  # Linux
                import subprocess
                subprocess.call(['xdg-open', file_path])
        except Exception as e:
            QMessageBox.warning(self, "无法打开文件", f"打开文件失败: {str(e)}") 